package com.zijidelu.luframework.utils.spring.beans.register;

import com.zijidelu.luframework.utils.CastUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.Optional;

/**
 * Spring动态Bean注册工具类
 * 提供完整的Bean动态注册功能，支持多种作用域和生命周期管理
 *
 * @author ZIJIDELU
 * @datetime 2025/10/12 10:30
 */
@Component
public class SpringDynamicBeanRegisterUtil implements DynamicBeanRegister {
    private final BeanDefinitionRegistry registry;
    private final ConfigurableApplicationContext context;

    @Autowired
    public SpringDynamicBeanRegisterUtil(ConfigurableApplicationContext context) {
        this.context = context;
        if (!(context.getBeanFactory() instanceof BeanDefinitionRegistry)) {
            throw new IllegalArgumentException("ApplicationContext does not support BeanDefinitionRegistry");
        }
        this.registry = (BeanDefinitionRegistry) context.getBeanFactory();
    }

    /**
     * 注册简单 Bean
     *
     * @param beanName  Bean 名称
     * @param beanClass Bean 类型
     * @throws IllegalArgumentException 当参数无效时
     * @throws RuntimeException         当Bean已存在或注册失败时
     */
    @Override
    public void registerBean(String beanName, Class<?> beanClass) {
        registerBean(beanName, beanClass, BeanDefinitionScopeEnum.SINGLETON);
    }

    /**
     * 注册指定作用域的 Bean
     *
     * @param beanName  Bean 名称
     * @param beanClass Bean 类型
     * @param scope     作用域
     * @throws IllegalArgumentException 当参数无效时
     * @throws RuntimeException         当Bean已存在或注册失败时
     */
    public void registerBean(String beanName, Class<?> beanClass, BeanDefinitionScopeEnum scope) {
        validateParameters(beanName, beanClass);

        synchronized (((DefaultListableBeanFactory) registry).getSingletonMutex()) {
            checkBeanNotExists(beanName);

            GenericBeanDefinition beanDefinition = createBeanDefinition(beanClass, scope.getScope());
            registry.registerBeanDefinition(beanName, beanDefinition);
        }
    }

    /**
     * 注册带属性的 Bean
     *
     * @param beanName   Bean 名称
     * @param beanClass  Bean 类型
     * @param properties Bean 属性
     * @throws IllegalArgumentException 当参数无效时
     * @throws RuntimeException         当Bean已存在或注册失败时
     */
    public void registerBeanWithProperties(String beanName, Class<?> beanClass, Map<String, Object> properties) {
        validateParameters(beanName, beanClass);

        synchronized (((DefaultListableBeanFactory) registry).getSingletonMutex()) {
            checkBeanNotExists(beanName);

            GenericBeanDefinition beanDefinition = createBeanDefinition(beanClass, BeanDefinition.SCOPE_SINGLETON);

            // 设置属性
            if (properties != null && !properties.isEmpty()) {
                properties.forEach((key, value) -> {
                    beanDefinition.getPropertyValues().add(key, value);
                });
            }

            registry.registerBeanDefinition(beanName, beanDefinition);
        }
    }

    /**
     * 注册带初始化/销毁方法的 Bean
     *
     * @param beanName      Bean 名称
     * @param beanClass     Bean 类型
     * @param initMethod    初始化方法名
     * @param destroyMethod 销毁方法名
     * @throws IllegalArgumentException 当参数无效或方法不存在时
     * @throws RuntimeException         当Bean已存在或注册失败时
     */
    public void registerBeanWithLifecycle(
            String beanName,
            Class<?> beanClass,
            String initMethod,
            String destroyMethod) {

        validateParameters(beanName, beanClass);

        synchronized (((DefaultListableBeanFactory) registry).getSingletonMutex()) {
            checkBeanNotExists(beanName);

            GenericBeanDefinition beanDefinition = createBeanDefinition(beanClass, BeanDefinition.SCOPE_SINGLETON);

            // 设置生命周期方法
            if (StringUtils.hasText(initMethod)) {
                validateMethodExists(beanClass, initMethod, "Init");
                beanDefinition.setInitMethodName(initMethod);
            }

            if (StringUtils.hasText(destroyMethod)) {
                validateMethodExists(beanClass, destroyMethod, "Destroy");
                beanDefinition.setDestroyMethodName(destroyMethod);
            }

            registry.registerBeanDefinition(beanName, beanDefinition);
        }
    }

    /**
     * 注册Bean并立即初始化
     *
     * @param beanName  Bean 名称
     * @param beanClass Bean 类型
     * @return 注册并初始化成功返回Bean实例
     * @throws RuntimeException 当注册或初始化失败时
     */
    public Object registerAndInitializeBean(String beanName, Class<?> beanClass) {
        // 先注册Bean
        registerBean(beanName, beanClass);

        try {
            // 然后获取Bean实例进行初始化
            return context.getBean(beanName);
        } catch (Exception e) {
            throw new RuntimeException("Failed to initialize bean: " + beanName, e);
        }
    }

    /**
     * 检查Bean是否已存在
     *
     * @param beanName Bean名称
     * @return 是否存在
     */
    @Override
    public boolean containsBean(String beanName) {
        return registry.containsBeanDefinition(beanName);
    }

    /**
     * 获取Bean实例（如果存在）
     *
     * @param beanName Bean名称
     * @return Bean实例，如果不存在返回null
     */
    @Override
    public Optional<?> getBeanIfExists(String beanName) {

        try {
            return context.containsBean(beanName)
                    ? Optional.of(context.getBean(beanName))
                    : Optional.empty();
        } catch (Exception e) {
            return Optional.empty();
        }

    }

    /**
     * 获取指定类型的Bean实例
     *
     * @param beanName Bean名称
     * @param beanType Bean类型
     * @return Bean实例，如果不存在返回null
     */
    @Override
    public <T> Optional<T> getBeanIfExists(String beanName, Class<T> beanType) {
        try {
            return context.containsBean(beanName) ? Optional.of(context.getBean(beanName, beanType)) : Optional.empty();
        } catch (Exception e) {
            return Optional.empty();
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> Optional<T> getBeanIfExists(Class<T> beanType) {
        return Optional.of(context.getBean(beanType));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> Map<String, T> getBeansOfType(Class<?> beanType) {
        return CastUtil.cast(context.getBeansOfType(beanType));
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 验证参数有效性
     */
    private void validateParameters(String beanName, Class<?> beanClass) {
        if (!StringUtils.hasText(beanName) || beanClass == null) {
            throw new IllegalArgumentException("Bean name and class cannot be null or empty");
        }
    }

    /**
     * 检查Bean是否已存在，如果存在则抛出异常
     */
    private void checkBeanNotExists(String beanName) {
        if (registry.containsBeanDefinition(beanName)) {
            throw new RuntimeException("Bean '" + beanName + "' already exists");
        }
    }

    /**
     * 创建Bean定义
     */
    private GenericBeanDefinition createBeanDefinition(Class<?> beanClass, String scope) {
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(beanClass);
        beanDefinition.setScope(scope);
        return beanDefinition;
    }

    /**
     * 验证方法是否存在
     */
    private void validateMethodExists(Class<?> beanClass, String methodName, String methodType) {
        try {
            beanClass.getDeclaredMethod(methodName);
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException(methodType + " method '" + methodName + "' not found in class " + beanClass.getName());
        }
    }

}